package ncrnadb.ncinetview.internal.request;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import ncrnadb.ncinetview.internal.cy.CyUtils;
import ncrnadb.ncinetview.internal.owrapper.EntityType;
import ncrnadb.ncinetview.internal.owrapper.ORDB;
import ncrnadb.ncinetview.internal.owrapper.RID;
import ncrnadb.ncinetview.internal.owrapper.RelationFields;

import org.apache.commons.collections.list.TreeList;
import org.cytoscape.model.CyColumn;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyNode;
import org.cytoscape.model.CyRow;

import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;


public class AllRequest {

	
	public CyNetwork network = null;
	public boolean addGene = false;
	public boolean addDisease = false;
	public boolean addRNA = false;
	public boolean addOthers = false;
	
	public AllRequest(){
		
	}
	
	
	public void solve(){
		if(network != null){
			CyUtils.addDefaultColumns(network);
			CyUtils.addORIDColumns(network);
			
			CyColumn typeCol = network.getDefaultNodeTable().getColumn(CyUtils.DefaultTypeColumnName);
			CyColumn aliasesCol = network.getDefaultNodeTable().getColumn(CyUtils.DefaultAliasesColumnName);
			
			Collection<EntityType> eTypes = new TreeSet<EntityType>();
			eTypes.add(EntityType.NCRNA);
			if(addGene) eTypes.add(EntityType.GENE);
			if(addRNA) eTypes.add(EntityType.RNA);
			if(addDisease) eTypes.add(EntityType.DISEASE);
			if(addOthers) eTypes.add(EntityType.OTHERS);
			
			
			
			ORDB ordb = new ORDB();
			ordb.open();
			
			
			
			/*===================================================================================================================*/
			System.out.println("retrieving nodes...");
			
			//map cynode -> bioentities
			Map<Long, Set<Vertex>> cy2ov = new TreeMap<Long, Set<Vertex>>();
			//map bioentity -> cynodes
			Map<Vertex, Set<Long>> ov2cy = new TreeMap<Vertex, Set<Long>>();
			
			
			for(EntityType eType : eTypes){
				Iterable<Vertex> ents = ordb.getEntitiesOfType(eType);
				
				for(Vertex v : ents){
					CyNode cnode = CyUtils.addEntityToNetwork(ordb, v, network, typeCol, aliasesCol);
					
					Long rowId = cnode.getSUID();
					//map cy to OR and viceversa
					Set<Long> nodes = ov2cy.get(v);
					if(nodes == null){
						nodes = new TreeSet<Long>();
						ov2cy.put(v, nodes);
					}
					
					Set<Vertex> verts = cy2ov.get(rowId);
					if(verts == null){
						verts = new TreeSet<Vertex>();
						cy2ov.put(rowId, verts);
					}
					
					nodes.add(rowId);
					verts.add(v);
				}
			}
			
			/*===================================================================================================================*/
			//expand network with db edges
			System.out.println("retrieving edges...");

			for(Edge ed : ordb.getRelationsAmong(ov2cy.keySet())){
				RelationFields rfs = ordb.getFields(ed);
				
				Collection<CyRow> matchingRows = network.getDefaultEdgeTable().getMatchingRows(CyUtils.ORIDEdgeColumnName, ed.getId().toString());
				if(matchingRows.isEmpty()){
					
					Collection<Long> sources = ov2cy.get(ed.getVertex(Direction.OUT));
					Collection<Long> targets = ov2cy.get(ed.getVertex(Direction.IN));
					
					for(Long s : sources){
						for(Long t : targets){
						
							CyEdge ced = network.addEdge(network.getNode(s), network.getNode(t), false);
							CyRow cedRow = network.getDefaultEdgeTable().getRow(ced.getSUID());
							cedRow.set("level", rfs.level);
							cedRow.set("pubmed", rfs.pubmedID);
							cedRow.set("support", rfs.supportSentence);
							cedRow.set("source", rfs.source.compact());
							cedRow.set(CyUtils.ORIDEdgeColumnName, ed.getId().toString());
						}
					}
				}
			}
			
			
			ordb.close();
		}
	}
	
}
